const FULFILLED = 'fulfilled';
const REJECTED = 'rejected';
const PENDING = 'pending';

class MyPromise {
    constructor(executor) {
        this.status = PENDING; // 状态
        this.value = undefined; // 数据
        this.errmsg = undefined; // 错误信息
        this.successCallback = []; // 成功回调
        this.failCallback = []; // 失败回调
        // 绑定this
        this.resolve = this.resolve.bind(this);
        this.reject = this.reject.bind(this);
        //调用执行器
        try { // 错误捕获
            executor(this.resolve, this.reject);
        } catch (e) {
            this.reject(e)
        }
    }
    resolve(value) {
        // 判断状态是否已改变，已改变的状态不能再次改变
        if (this.status !== PENDING) return;
        // 将状态从pending--> fulfilled
        this.status = FULFILLED;
        // 保存数据
        this.value = value;
        // 调用成功回调
        while(this.successCallback.length) this.successCallback.shift()();
    }
    reject(errmsg) {
        // 判断状态是否已改变，已改变的状态不能再次改变
        if (this.status !== PENDING) return;
        // 将状态从pending--> rejected
        this.status = REJECTED;
        // 保存失败信息
        this.errmsg = errmsg;
        // 调用失败回调
        while(this.failCallback.length) this.failCallback.shift()();
    }
    then(successCallback, failCallback) {
        successCallback = successCallback ? successCallback : value=>value;
        failCallback = failCallback ? failCallback : err=>{throw err};
        let newPromise = new MyPromise((resolve, reject)=> {
            if (this.status === FULFILLED) { // 成功
                const _this = this;
                setTimeout(function() {
                    try { // 错误捕获
                        let x= successCallback(_this.value);
                        // 判断x的值是普通纸还是promise对象
                        // 普通值直接调用resolve
                        // promise对象 需查看promise对象返回结果
                        // 根据返回结果决定调用resolve还是rejec
                        resolvePromise(newPromise, x, resolve, reject);
                    } catch (e) {
                        reject(e)
                    }
                },0);
            } else if (this.status === REJECTED) { // 失败
                const _this = this;
                setTimeout(function() {
                    try { // 错误捕获
                        let x= failCallback(_this.errmsg);
                        // 判断x的值是普通纸还是promise对象
                        // 普通值直接调用resolve
                        // promise对象 需查看promise对象返回结果
                        // 根据返回结果决定调用resolve还是rejec
                        resolvePromise(newPromise, x, resolve, reject);
                    } catch (e) {
                        reject(e)
                    }
                },0);
            } else { // 等待
                // 缓存成功回调
                this.successCallback.push(()=>{
                    const _this = this;
                    setTimeout(function() {
                        try { // 错误捕获
                            let x= successCallback(_this.value);
                            // 判断x的值是普通纸还是promise对象
                            // 普通值直接调用resolve
                            // promise对象 需查看promise对象返回结果
                            // 根据返回结果决定调用resolve还是rejec
                            resolvePromise(newPromise, x, resolve, reject);
                        } catch (e) {
                            reject(e)
                        }
                    },0);
                });
                // 缓存失败会掉
                this.failCallback.push(()=>{
                    const _this = this;
                    setTimeout(function() {
                        try { // 错误捕获
                            let x= failCallback(_this.errmsg);
                            // 判断x的值是普通纸还是promise对象
                            // 普通值直接调用resolve
                            // promise对象 需查看promise对象返回结果
                            // 根据返回结果决定调用resolve还是rejec
                            resolvePromise(newPromise, x, resolve, reject);
                        } catch (e) {
                            reject(e)
                        }
                    },0);
                });
            }
        });
        return newPromise;
    }
    finally (callback) {
        return this.then((value)=>{
            return MyPromise.resolve(callback()).then(()=>value)
        },(err)=>{
            return MyPromise.resolve(callback()).then(()=>{throw err})
        });
    }
    catch (failCallback) {
        return this.then(undefined, failCallback)
    }
    static all (arr) {
        let result = [];
        let num = 0;
        return new MyPromise((resolve,reject)=> {
            function addData(key, value) {
                result[key] = value;
                num++;
                if (num === arr.length) { //通过num是否等于数组长度，判断请求是否都成功返回
                    resolve(result)
                }
            }
            for (let i=0; i<arr.length; i++) {
                let current = arr[i];
                if (current instanceof MyPromise) { // promise对象
                    current.then(value=>addData(i,value),reject);
                } else {
                    addData(i, arr[i])
                }
            }
        })
    }
    /**
     * 判断value类型
     * value 为 promise对象，则直接返回
     * value 为普通值，需new一个promise对象并调用resolve方法
     */
    static resolve (value) {
        if (value instanceof MyPromise) return value;
        return new MyPromise(resolve => resolve(value));
    }
}
function resolvePromise(oldPromise, x, resolve, reject) {
    if (oldPromise === x) { // 排除promise对象的循环调用
        return reject(new TypeError('Chaining cycle detected for promise #<Promise>'))
    }
    if (x instanceof MyPromise) { // promise对象
        return x.then(resolve,reject);
    } else { // 普通值
        return resolve(x);
    }
}


module.exports = MyPromise;